import type { MouseEvent } from 'react';

import { AnimatePresence, motion } from 'motion/react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { generatePath, Link } from 'react-router';

import styles from './feature-carousel.module.css';

import { usePlayer } from '/@/renderer/features/player/context/player-context';
import { BackgroundOverlay } from '/@/renderer/features/shared/components/library-background-overlay';
import { PlayButtonGroup } from '/@/renderer/features/shared/components/play-button-group';
import { useContainerQuery, useFastAverageColor } from '/@/renderer/hooks';
import { AppRoute } from '/@/renderer/router/routes';
import { useCurrentServer } from '/@/renderer/store';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Badge } from '/@/shared/components/badge/badge';
import { Group } from '/@/shared/components/group/group';
import { Image } from '/@/shared/components/image/image';
import { Stack } from '/@/shared/components/stack/stack';
import { TextTitle } from '/@/shared/components/text-title/text-title';
import { Text } from '/@/shared/components/text/text';
import { Album, LibraryItem } from '/@/shared/types/domain-types';
import { Play } from '/@/shared/types/types';

const containerVariants = {
    animate: (custom: { isNext: boolean }) => ({
        transition: {
            delayChildren: 0.1,
            staggerChildren: 0.3,
            staggerDirection: custom.isNext ? 1 : -1,
        },
    }),
    exit: (custom: { isNext: boolean }) => ({
        transition: {
            staggerChildren: 0.3,
            staggerDirection: custom.isNext ? 1 : -1,
        },
    }),
    initial: (custom: { isNext: boolean }) => ({
        transition: {
            staggerChildren: 0.3,
            staggerDirection: custom.isNext ? -1 : 1,
        },
    }),
};

const itemVariants = {
    animate: {
        opacity: 1,
        scale: 1,
        transition: {
            duration: 0.4,
            ease: 'easeOut' as const,
        },
        y: 0,
    },
    exit: {
        opacity: 0,
        scale: 0.8,
        transition: {
            duration: 0.3,
            ease: 'easeIn' as const,
        },
        y: -20,
    },
    initial: {
        opacity: 0,
        y: 20,
    },
};

interface FeatureCarouselProps {
    data: Album[] | undefined;
    onNearEnd?: () => void;
}

const getItemsPerRow = (breakpoints: {
    is2xl: boolean;
    is3xl: boolean;
    isLg: boolean;
    isMd: boolean;
    isSm: boolean;
    isXl: boolean;
}) => {
    if (breakpoints.is3xl) return 6;
    if (breakpoints.is2xl) return 5;
    if (breakpoints.isXl) return 5;
    if (breakpoints.isLg) return 4;
    if (breakpoints.isMd) return 3;
    if (breakpoints.isSm) return 2;
    return 2;
};

interface CarouselItemProps {
    album: Album;
}

const CarouselItem = ({ album }: CarouselItemProps) => {
    const { background: backgroundColor } = useFastAverageColor({
        algorithm: 'dominant',
        src: album.imageUrl || null,
        srcLoaded: true,
    });

    const server = useCurrentServer();
    const { addToQueueByFetch } = usePlayer();

    const handlePlay = (type: Play) => {
        if (!server?.id) return;
        addToQueueByFetch(server.id, [album.id], LibraryItem.ALBUM, type);
    };

    return (
        <div className={styles.carouselItem}>
            <BackgroundOverlay backgroundColor={backgroundColor} opacity={0.7} />
            <Link
                className={styles.carouselLink}
                state={{ item: album }}
                to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, {
                    albumId: album.id,
                })}
            >
                <div className={styles.content}>
                    <div className={styles.titleSection}>
                        <TextTitle className={styles.title} fw={800} lineClamp={2} order={3}>
                            {album.name}
                        </TextTitle>
                    </div>

                    <div className={styles.imageSection}>
                        <Image
                            className={styles.albumImage}
                            containerClassName={styles.albumImageContainer}
                            src={album.imageUrl || undefined}
                        />
                        <div className={styles.playButtonOverlay}>
                            <PlayButtonGroup onPlay={handlePlay} />
                        </div>
                    </div>

                    <div className={styles.metadataSection}>
                        <Stack gap="sm">
                            {album.albumArtists.slice(0, 1).map((artist) => (
                                <Text
                                    className={styles.artist}
                                    fw={600}
                                    key={`artist-${artist.id}`}
                                    size="xl"
                                >
                                    {artist.name}
                                </Text>
                            ))}
                            <Group gap="sm" justify="center" wrap="wrap">
                                {album.genres?.slice(0, 2).map((genre) => (
                                    <Badge
                                        key={`genre-${genre.id}`}
                                        size="lg"
                                        variant="transparent"
                                    >
                                        {genre.name}
                                    </Badge>
                                ))}
                                {album.releaseYear && (
                                    <Badge size="lg" variant="transparent">
                                        {album.releaseYear}
                                    </Badge>
                                )}
                            </Group>
                        </Stack>
                    </div>
                </div>
            </Link>
        </div>
    );
};

export const FeatureCarousel = ({ data, onNearEnd }: FeatureCarouselProps) => {
    const [startIndex, setStartIndex] = useState(0);
    const directionRef = useRef<{ isNext: boolean }>({ isNext: true });
    const {
        is2xl,
        is3xl,
        isLg,
        isMd,
        isSm,
        isXl,
        ref: containerRef,
    } = useContainerQuery({
        '2xl': 1920,
        '3xl': 2560,
        lg: 1024,
        md: 768,
        sm: 640,
        xl: 1440,
    });

    const itemsPerRow = useMemo(
        () => getItemsPerRow({ is2xl, is3xl, isLg, isMd, isSm, isXl }),
        [is2xl, is3xl, isLg, isMd, isSm, isXl],
    );

    const visibleItems = useMemo(() => {
        if (!data) return [];
        const items: Album[] = [];
        for (let i = 0; i < itemsPerRow; i++) {
            const index = (startIndex + i) % data.length;
            items.push(data[index]);
        }
        return items;
    }, [data, startIndex, itemsPerRow]);

    // Check if we're near the end and trigger loading more
    useEffect(() => {
        if (!data || !onNearEnd) return;
        const remainingItems = data.length - startIndex;
        // Trigger when we have less than 2 rows worth of items remaining
        if (remainingItems < itemsPerRow * 2) {
            onNearEnd();
        }
    }, [data, startIndex, itemsPerRow, onNearEnd]);

    const handleNext = (e?: MouseEvent<HTMLButtonElement>) => {
        e?.preventDefault();
        e?.stopPropagation();
        if (!data) return;
        directionRef.current = { isNext: true };
        setStartIndex((prev) => (prev + itemsPerRow) % data.length);
    };

    const handlePrevious = (e?: MouseEvent<HTMLButtonElement>) => {
        e?.preventDefault();
        e?.stopPropagation();
        if (!data) return;
        directionRef.current = { isNext: false };
        setStartIndex((prev) => (prev - itemsPerRow + data.length) % data.length);
    };

    if (!data || data.length === 0) {
        return null;
    }

    return (
        <div className={styles.carouselContainer} ref={containerRef}>
            <AnimatePresence initial={false} mode="popLayout">
                <motion.div
                    animate="animate"
                    className={styles.carousel}
                    custom={directionRef.current}
                    exit="exit"
                    initial="initial"
                    key={`carousel-${startIndex}`}
                    style={{ '--items-per-row': itemsPerRow } as React.CSSProperties}
                    variants={containerVariants}
                >
                    {visibleItems.map((album, index) => (
                        <motion.div
                            key={`item-${album.id}-${startIndex}-${index}`}
                            variants={itemVariants}
                        >
                            <CarouselItem album={album} />
                        </motion.div>
                    ))}
                </motion.div>
            </AnimatePresence>

            {data.length > itemsPerRow && (
                <>
                    <ActionIcon
                        className={styles.navArrowLeft}
                        icon="arrowLeftS"
                        iconProps={{ size: 'xl' }}
                        onClick={handlePrevious}
                        radius="50%"
                        size="md"
                        variant="subtle"
                    />
                    <ActionIcon
                        className={styles.navArrowRight}
                        icon="arrowRightS"
                        iconProps={{ size: 'xl' }}
                        onClick={handleNext}
                        radius="50%"
                        size="md"
                        variant="subtle"
                    />
                </>
            )}
        </div>
    );
};
